
#include "area.h"
#include "creature.h"
#include "commandTable-default.h"
#include "handler.h"
#include "object.h"
#include "room.h"
#include "symphony.h"

Creature::Creature( void ) {
  ID( 0 );
  level( 0 );
  typeFlags( 0 );
  gender( NEUTRAL );
  mode( 0 );
  return;
}

Creature::Creature( const Creature& ref ) {
  ID( ref.ID() );
  name( ref.name() );
  brief( ref.brief() );
// keywords
  description( ref.description() );
  level( ref.level() );
  typeFlags( ref.typeFlags() );
  gender( ref.gender() );
  mode( ref.mode() );
  return;
}

Creature::~Creature( void ) {
  for ( std::vector<Handler*>::iterator it = handlers().begin(); handlers().size(); ) {
    delete *it;
    it = handlers().erase( it );
  }
  while( objects().size() ) {
    delete objects().front();
    objects().pop_front();
  }
  return;
}

Handler* Creature::handler( void ) { // public
  return handlers().back();
}

void Creature::pushHandler( Handler* handler ) { // public
  handlers().push_back( handler );
  handler->activate();
  return;
}

void Creature::popHandler( void ) { // public
  handlers().back()->deactivate();
  handlers().pop_back();
  return;
}

void Creature::replaceHandler( Handler* handler ) { // public
  popHandler();
  pushHandler( handler );
  return;
}

void Creature::handle( void ) { // public
  handlers().back()->handle();
  return;
}

void Creature::add( Object* object ) { // public
  objects().push_front( object );
  return;
}

void Creature::remove( Object* object ) { // public
  objects().remove( object );
  return;
}

Object* Creature::findObject( const std::string& name, unsigned scope ) { // public
  if ( ( scope & SEARCH_CARRY ) == SEARCH_CARRY ) {
    for ( std::list<Object*>::iterator it = objects().begin(); it != objects().end(); ++it ) {
      if ( (*it)->matchesKeyword( name ) && canSee( *it ) == SEE_NAME ) {
        return *it;
      }
    }
  }
  if ( ( scope & SEARCH_ROOM ) == SEARCH_ROOM ) {
    for ( std::list<Object*>::iterator it = room()->objects().begin(); it != room()->objects().end(); ++it ) {
      if ( (*it)->matchesKeyword( name ) && canSee( *it ) == SEE_NAME ) {
        return *it;
      }
    }
  }
  return NULL;
}

Creature* Creature::findCreature( const std::string& name, unsigned scope ) { // public
  Creature* creature = NULL;
  if ( ( scope & SEARCH_ROOM ) == SEARCH_ROOM ) {
    for ( std::list<Creature*>::iterator it = room()->creatures().begin(); it != room()->creatures().end(); ++it ) {
      if ( (*it)->matchesKeyword( name ) && canSee( *it ) == SEE_NAME ) {
        return *it;
      }
    }
  }
  if ( ( scope & SEARCH_WORLD ) == SEARCH_WORLD ) {
    if ( ( creature = World::Instance().findCreature( name ) ) != NULL ) {
      return creature;
    }
  }
  return NULL;
}

void Creature::room( Room* room ) { // public
  CmdExit exit;
  _room = room;
  if ( mode() == MODE_REDIT ) {
    if ( !World::Instance().hasPermission( room->area(), (Avatar*)this ) ) {
      exit.execute( this, "" );
      return;
    }
    // Make sure no one else is editing the room...
    for ( std::map<std::string,Avatar*>::iterator it = World::Instance().getAvatars().begin(); it != World::Instance().getAvatars().end(); ++it ) {
      if ( it->second != this && it->second->mode() == MODE_REDIT && it->second->room() == room ) {
        send( "Sorry, %s is already editing this room.", seeName( ((Creature*)it->second) ).c_str() );
        exit.execute( this, "" );
        return;
      }
    }
  }
  return;
}

const char* Creature::genderName( void ) const { // public
  switch ( gender() ) {
    case MALE:    return "male";    break;
    case FEMALE:  return "female";  break;
    default:      return "neutral"; break;
  }
}

unsigned short Creature::canSee( Creature* target ) { // public

  // Check for immortal invisibility...
  if ( target->admin( ADMIN_INVIS ) && target->level() > level() ) {
    return SEE_NOTHING;
  }

  return SEE_NAME;
}

std::string Creature::seeName( Creature* target, bool capitalize ) { // public
  if ( canSee( target ) == SEE_NAME ) {
    return target->name();
  } else {
    if ( capitalize ) {
      return "Someone";
    } else {
      return "someone";
    }
  }
}

unsigned short Creature::canSee( Object* target ) { // public
  return SEE_NAME;
}

std::string Creature::seeName( Object* target, bool capitalize ) { // public
  if ( canSee( target ) == SEE_NAME ) {
    return target->shortname();
  } else {
    if ( capitalize ) {
      return "Something";
    } else {
      return "something";
    }
  }
}

bool Creature::canAlter( Creature* target ) { // public
  return ( target->level() < level()-2 );
}

bool Creature::canMove( const unsigned short& direction, std::string& message ) { // public
  Exit* exit = NULL;

  if ( ( exit = room()->exit( direction ) ) == NULL ) {
    message.append( "You cannot go that way." );
    return false;
  }

  if ( exit->flag( EFLAG_CLOSED ) ) {
    message.append( "That door is closed." );
    return false;
  }

  return true;
}

void Creature::move( const unsigned short& direction ) { // public
  Exit* exit = room()->exit( direction );
  Room* from = room();
  Room* to = exit->target();
  CmdLook look;

  // Make the switch...
  from->remove( this );
  to->add( this );
  room( to );

  // Send some output...
  send( "You leave %s.\n", Exit::name( direction ) );
  from->send_cond( "$p leaves to the $e.", this, exit );
  to->send_cond( "$p has arrived from the $n.", this, exit );

  look.execute( this, "" );

  return;
}

